package com.ebupt.migu.music.popup.service.impl;


import com.alibaba.fastjson.JSONObject;
import com.ebupt.migu.globalpopup.entity.*;
import com.ebupt.migu.globalpopup.enums.ConditionEnum;
import com.ebupt.migu.music.commons.constants.ResultMsg;
import com.ebupt.migu.music.commons.utils.ConditionUtil;
import com.ebupt.migu.music.commons.utils.DateUtil;
import com.ebupt.migu.music.popup.dto.ActivityDetailDTO;
import com.ebupt.migu.music.popup.dto.ActivityHitDTO;
import com.ebupt.migu.music.popup.service.ActivityService;
import com.ebupt.migu.music.popup.vo.ActivityDetailVO;
import com.ebupt.migu.music.popup.vo.PlayTrigVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 服务云全局弹窗接口
 *
 * @author wangzhu
 * @since 2021-11-17
 */
@Service
@Slf4j
public class ActivityServiceImpl implements ActivityService {

    @Autowired
    private RedisTemplate redisTemplate;

    private static String AID_UID_KEY = "AID_UID_KEY";

    private static String FRE_UID_KEY = "FRE_UID_KEY";

    @Value("${app.version}")
    private String appVersion;

    @Override
    public ResultMsg getDetail(ActivityDetailDTO activityDetailDTO) {
        ResultMsg resultMsg = new ResultMsg();
        String redisKey = "popup-" + activityDetailDTO.getActivityId();
        ActivityDetailVO redisData = getRedisData(redisKey, activityDetailDTO);
        if (null != redisData) {
            resultMsg.setData(redisData);
        }
        resultMsg.setMessage("SUCCESS");
        return resultMsg;
    }

    @Override
    public ResultMsg getBatch(ActivityDetailDTO activityDetailDTO) {
        ResultMsg resultMsg = new ResultMsg();
        List<ActivityDetailVO> list = new ArrayList<>();
        String[] ids = activityDetailDTO.getActivityId().split(",");
        String redisKey;
        ActivityDetailVO redisData;
        for (String id : ids) {
            redisKey = "popup-" + id;
            redisData = getRedisData(redisKey, activityDetailDTO);
            if (null != redisData) {
                list.add(redisData);
            }
        }
        resultMsg.setData(list);
        resultMsg.setMessage("SUCCESS");
        return resultMsg;
    }

    private ActivityDetailVO getRedisData(String redisKey, ActivityDetailDTO activityDetailDTO) {
        try {
            if (redisTemplate.hasKey(redisKey)) {
                ActivityRedisBean activityRedisBean = JSONObject.parseObject(Objects.requireNonNull(redisTemplate.opsForValue().get(redisKey)).toString(), ActivityRedisBean.class);
                //各种判断处理
                List<ConditionRelation> conditionRelations = activityRedisBean.getConditionRelations();
                if (conditionRelations.size() > 0) {
                    ConditionUtil conditionTool = ConditionUtil.getConditionUtil();
                    boolean flag = conditionTool.getCondition(activityDetailDTO.getExtra(), conditionRelations);
                    if (!flag) {
                        return null;
                    }
                }

                //查寻是否已有弹窗
                boolean flag = redisTemplate.hasKey(AID_UID_KEY + ":" + activityDetailDTO.getDeviceId() + "-" + activityDetailDTO.getActivityId());
                ActivityInfo activityInfoForPop = activityRedisBean.getActivityInfo();
                //判断活动是否配置的是每次都弹出
                if (activityInfoForPop.getActivityTimes() == -1) {
                    flag = false;
                }
                log.info("用户id：{},活动id：{},是否触发：{}", activityDetailDTO.getDeviceId(), activityDetailDTO.getActivityId(), !flag);
                if (!flag) {
                    ActivityDetailVO activityDetailVO = appVersion(activityDetailDTO.getExtra(),appVersion) ? new ActivityDetailVO() : new PlayTrigVO();
                    ActivityInfo activityInfo = activityRedisBean.getActivityInfo();
                    ActionInfo actionInfo = activityRedisBean.getActionInfo();
                    PopupInfo popupInfo = getPopupInfo(activityInfo.getActivityId(),activityRedisBean.getPopupInfos());
                    BeanUtils.copyProperties(activityInfo, activityDetailVO);
                    BeanUtils.copyProperties(actionInfo, activityDetailVO);
                    BeanUtils.copyProperties(popupInfo, activityDetailVO);
                    log.info("活动明细：{}", activityDetailVO);
                    return activityDetailVO;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private boolean appVersion(Map data,String version){
        Object obj = data.get(ConditionEnum.VERSION.getValue());
        if (obj != null) {
            return obj.toString().compareTo(version) < 0;
        }
        return true;
    }

    @Override
    public ResultMsg getHit(ActivityHitDTO activityHitDTO) {
        ResultMsg resultMsg = new ResultMsg();
        try {
            String activityId = activityHitDTO.getActivityId();
            String redisKey = "popup-" + activityId;
            if (redisTemplate.hasKey(redisKey)) {
                ActivityRedisBean activityRedisBean = JSONObject.parseObject(Objects.requireNonNull(redisTemplate.opsForValue().get(redisKey)).toString(), ActivityRedisBean.class);

                //将用户成功弹窗次数存入redis
                getFreSet(activityHitDTO.getDeviceId());

                Integer times = activityRedisBean.getActivityInfo().getActivityTimes();
                if (times != -1) {
                    //主动删除过期key
                    redisTemplate.unlink(AID_UID_KEY + ":" + activityHitDTO.getDeviceId() + "-" + activityId);
                    // 获取时区原始偏移量
                    long tmp = new BigDecimal(TimeZone.getDefault().getRawOffset()).longValue();
                    // 获取当前时间
                    long nowTime = System.currentTimeMillis();
                    //计算过期时间
                    long ms = (nowTime + tmp) / (1000L * 3600L * 24L) * (1000L * 3600L * 24L) - tmp + 1000L * 3600L * 24L * times.longValue() - nowTime;
                    log.info("弹窗上报：key：{},times：{}, ms：{}", AID_UID_KEY + ":" + activityHitDTO.getDeviceId() + "-" + activityId, times, ms);
                    //存入redis并且设置过期时间
                    redisTemplate.opsForValue().set(AID_UID_KEY + ":" + activityHitDTO.getDeviceId() + "-" + activityId, "", ms, TimeUnit.MILLISECONDS);
                }
            }
            resultMsg.setMessage("SUCCESS");
        } catch (Exception e) {
            resultMsg.setCode("9999");
            resultMsg.setMessage("系统异常");
            e.printStackTrace();
            log.info("上报接口异常：" + e.getMessage());
            try {
                log.info("上报接口异常明细：" + e.toString());
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
        return resultMsg;
    }

    private void getFreSet(String deviceId) {
        //获取redis全局设置
        Object FrequencySet = redisTemplate.opsForValue().get("activityFrequencySwitch");
        if (FrequencySet != null) {
            String redisKey = FRE_UID_KEY + ":" + deviceId;
            //设置自增
            Long increment = redisTemplate.opsForValue().increment(redisKey, 1);
            log.info("用户id：{},自增值：{},更新后的次数：{}", deviceId, 1, increment);
            //设置有效时间-每晚的23:59:59
            if (increment == 1) {
                Date currentTime = new Date();
                Date endTime = DateUtil.getDayEndTime(currentTime);
                Long expireTime = endTime.getTime() - currentTime.getTime();
                redisTemplate.expire(redisKey, expireTime, TimeUnit.MILLISECONDS);
                log.info("用户id：{},截至时间：{},生命周期：{}", deviceId, endTime.toString(), expireTime);
            }
        }
    }

    /**
     * 多文案均分下发策略
     */
    private PopupInfo getPopupInfo(String activityId, List<PopupInfo> popupInfos) {
        //判断是否存在默认文案
        Optional<PopupInfo> info = popupInfos.stream().filter(e -> e.getIsDefault().equals(1)).findFirst();
        if (info.isPresent()) {
            return info.get();
        }
        //不存在默认文案时
        Long incr = redisTemplate.opsForValue().increment("incr-" + activityId, 1);
        AtomicLong al = new AtomicLong();
        Optional.ofNullable(incr).ifPresent(i -> al.set(incr % popupInfos.size()));
        int index = Math.toIntExact(al.get() == 0 ? popupInfos.size() : al.get());
        Optional<PopupInfo> any = popupInfos.stream().filter(e -> e.getActivityCid().equals(activityId + "_" + index)).findFirst();
        return any.orElse(null);
    }

}
